/**
 * Created with IntelliJ IDEA.
 * User: alunyov
 * Date: 5/30/13
 * Time: 5:37 PM
 */
package com.google.code.bankagregator.adapter.bank.aval.parsers.deposits;

import com.google.code.bankagregator.adapter.exception.AdapterConnectException;
import com.google.code.bankagregator.adapter.exception.AdapterException;
import com.google.code.bankagregator.adapter.exception.AdapterRecognizeDataException;
import com.google.code.bankagregator.common.SiteConnect;
import com.google.code.bankagregator.common.reader.DepositReader;
import com.google.code.bankagregator.entities.Currency;
import com.google.code.bankagregator.entities.Deposit;
import com.google.code.bankagregator.entities.DepositType;
import com.google.code.bankagregator.entities.State;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class AvalDepositClassicParser extends AbstractAvalDeposit implements DepositReader {

    private final int MIN_AMOUNT_UAH = 2000;
    private final int MIN_AMOUNT_USD = 500;
    private final int MIN_AMOUNT_EUR = 500;

    private Document doc = null;
    private String depositTitle = null;

    public AvalDepositClassicParser(String url) {
        super(url);
    }

    private List<Deposit> parseDepositsUAH() throws AdapterConnectException, AdapterRecognizeDataException {
        List<Deposit> deposits = new ArrayList<>();

        Element depositsTableUAH = doc.select("#bar-center table").get(DEPOSIT_UAH);
        Elements termsElements = depositsTableUAH.select("tr").get(DEPOSIT_UAH_TERMS).select("td");
        Map<String, Integer> termsMap = normalizeTerms(termsElements);

        Integer[] rowsInfo = new Integer[]{DEPOSIT_UAH_LESS_100K, DEPOSIT_UAH_MORE_100K};
        for (int row : rowsInfo) {
            Elements depositsElements = depositsTableUAH.select("tr").get(row).select("td");
            String amountTitle = depositsElements.get(0).text();
            int amount = Integer.parseInt(amountTitle.replaceAll("[^0-9]+", ""));
            int minAmount = 0;
            int maxAmount = 0;
            for (int i = 1; i < depositsElements.size(); i++) {
                Element rateElement = depositsElements.get(i);
                String rateString = rateElement.text();
                rateString = rateString.replace(",", ".");
                rateString = rateString.replaceAll("[^0-9.]+", "");
                Double rate = Double.parseDouble(rateString);

                Deposit deposit = new Deposit();
                deposit.setName(depositTitle);
                deposit.setDepositRate(rate);
                deposit.setCurrency(Currency.UAH);
                deposit.setBank(getBank());
                deposit.setUrl(getDepositPageURL());

                int term = termsMap.get(termsElements.get(i).text());
                deposit.setTerm(term);

                // TODO: replace with proper parsing for min/max amounts
                if (row == DEPOSIT_UAH_LESS_100K) {
                    minAmount = MIN_AMOUNT_UAH;
                    maxAmount = amount;
                } else if (row == DEPOSIT_UAH_MORE_100K) {
                    minAmount = amount;
                    maxAmount = Integer.MAX_VALUE;
                }
                deposit.setMinAmount(minAmount);
                deposit.setMaxAmount(maxAmount);
                deposit.setState(State.ACTIVE);
                deposit.setType(DepositType.Deposit);

                deposits.add(deposit);
            }
        }

        return deposits;
    }

    private List<Deposit> parseDepositsUSD() throws AdapterConnectException, AdapterRecognizeDataException {
        List<Deposit> deposits = new ArrayList<>();

        Element depositsTableUSD = doc.select("#bar-center table").get(DEPOSIT_USD);
        Elements termsElements = depositsTableUSD.select("tr").get(DEPOSIT_USD_TERMS).select("td");
        Map<String, Integer> termsMap = normalizeTerms(termsElements);

        Integer[] rowsInfo = new Integer[]{DEPOSIT_USD_LESS_10K, DEPOSIT_USD_MORE_10K};
        for (int row : rowsInfo) {
            Elements depositsElements = depositsTableUSD.select("tr").get(row).select("td");
            String amountTitle = depositsElements.get(0).text();
            int amount = Integer.parseInt(amountTitle.replaceAll("[^0-9]+", ""));
            int minAmount = 0;
            int maxAmount = 0;
            for (int i = 1; i < depositsElements.size(); i++) {
                Element rateElement = depositsElements.get(i);
                String rateString = rateElement.text();
                rateString = rateString.replace(",", ".");
                rateString = rateString.replaceAll("[^0-9.]+", "");
                Double rate = Double.parseDouble(rateString);

                Deposit deposit = new Deposit();
                deposit.setName(depositTitle);
                deposit.setDepositRate(rate);
                deposit.setCurrency(Currency.USD);
                deposit.setBank(getBank());
                deposit.setUrl(getDepositPageURL());

                int term = termsMap.get(termsElements.get(i).text());
                deposit.setTerm(term);

                // TODO: replace with proper parsing for min/max amounts
                if (row == DEPOSIT_USD_LESS_10K) {
                    minAmount = MIN_AMOUNT_USD;
                    maxAmount = amount;
                } else if (row == DEPOSIT_USD_MORE_10K) {
                    minAmount = amount;
                    maxAmount = Integer.MAX_VALUE;
                }
                deposit.setMinAmount(minAmount);
                deposit.setMaxAmount(maxAmount);
                deposit.setState(State.ACTIVE);
                deposit.setType(DepositType.Deposit);

                deposits.add(deposit);
            }
        }

        return deposits;
    }

    private List<Deposit> parseDepositsEUR() throws AdapterConnectException, AdapterRecognizeDataException {
        List<Deposit> deposits = new ArrayList<>();

        Element depositsTableUSD = doc.select("#bar-center table").get(DEPOSIT_EUR);
        Elements termsElements = depositsTableUSD.select("tr").get(DEPOSIT_EUR_TERMS).select("td");
        Map<String, Integer> termsMap = normalizeTerms(termsElements);

        Integer[] rowsInfo = new Integer[]{DEPOSIT_EUR_LESS_4K, DEPOSIT_EUR_4K_8K, DEPOSIT_EUR_8K_16K, DEPOSIT_EUR_16K_40K, DEPOSIT_EUR_MORE_40K};
        for (int row : rowsInfo) {
            Elements depositsElements = depositsTableUSD.select("tr").get(row).select("td");
            String amountTitle = depositsElements.get(0).text();
            amountTitle = amountTitle.replaceAll(" ", "");
            amountTitle = amountTitle.replaceAll("[^0-9—]+", "");
            String[] amounts = amountTitle.split("—");
            int minAmount = 0;
            int maxAmount = 0;
            for (int i = 1; i < depositsElements.size(); i++) {
                if (row == DEPOSIT_EUR_LESS_4K) {
                    minAmount = MIN_AMOUNT_EUR;
                    maxAmount = Integer.parseInt(amounts[0]);
                } else if (row == DEPOSIT_EUR_4K_8K || row == DEPOSIT_EUR_8K_16K || row == DEPOSIT_EUR_16K_40K) {
                    minAmount = Integer.parseInt(amounts[0]);
                    maxAmount = Integer.parseInt(amounts[1]);
                } else if (row == DEPOSIT_EUR_MORE_40K) {
                    minAmount = Integer.parseInt(amounts[0]);
                    maxAmount = Integer.MAX_VALUE;
                }
                Element rateElement = depositsElements.get(i);
                String rateString = rateElement.text();
                rateString = rateString.replace(",", ".");
                rateString = rateString.replaceAll("[^0-9.]+", "");
                Double rate = Double.parseDouble(rateString);

                Deposit deposit = new Deposit();
                deposit.setName(depositTitle);
                deposit.setDepositRate(rate);
                deposit.setCurrency(Currency.EUR);
                deposit.setBank(getBank());
                deposit.setUrl(getDepositPageURL());

                int term = termsMap.get(termsElements.get(i).text());
                deposit.setTerm(term);

                // TODO: replace with proper parsing for min/max amounts
                deposit.setMinAmount(minAmount);
                deposit.setMaxAmount(maxAmount);
                deposit.setState(State.ACTIVE);
                deposit.setType(DepositType.Deposit);

                deposits.add(deposit);
            }
        }

        return deposits;
    }

    @Override
    public List<Deposit> getDeposits() throws AdapterException {
        doc = new SiteConnect(getDepositPageURL()).getPage();
        depositTitle = doc.select("#bar-center h1").get(0).text();
        List<Deposit> deposits = new ArrayList<>();
        deposits.addAll(parseDepositsUAH());
        deposits.addAll(parseDepositsUSD());
        deposits.addAll(parseDepositsEUR());
        return deposits;
    }
}
